﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YArchitech.Revit;

namespace YJKDragCurveJig
{
	public class JigCreator
	{
		public JigCreator(ExternalCommandData commandData)
		{
			this.m_Revit = commandData;
			this.m_UiApp = commandData.Application;
			this.m_UiDoc = this.m_UiApp.ActiveUIDocument;
			this.m_App = this.m_UiApp.Application;
			this.m_Doc = this.m_UiDoc.Document;
		}

		~JigCreator()
		{
			if (this.m_KeyboardHook != null)
			{
				this.m_KeyboardHook.HookStop();
			}
		}

		public Result Initialize(List<JigEdgeInfo> curveInfoList, List<JigTextInfo> textInfoList, XYZ ptBase, ref string message)
		{
			Result result2;
			try
			{
				Result result = this.NewFamilyDocument(ref message);
				if (result != Result.Succeeded)
				{
					result2 = result;
				}
				else
				{
					this.m_FamilyCreator = new JigFamilyCreator(this.m_Revit, this.m_FamilyDocument);
					result = this.m_FamilyCreator.CreateJIGFamily(curveInfoList, textInfoList, ptBase, ref message);
					if (result != Result.Succeeded)
					{
						this.DocumentClose();
						result2 = result;
					}
					else
					{
						result = this.SaveFamilyFile();
						if (result != Result.Succeeded)
						{
							this.DocumentClose();
							result2 = result;
						}
						else
						{
							result2 = result;
						}
					}
				}
			}
			catch (Exception ex)
			{
				message = ex.Message;
				this.ClearTempFiles();
				result2 = Autodesk.Revit.UI.Result.Failed;
			}
			return result2;
		}

		public bool Do(ref XYZ ptInsert)
		{
			if (this.m_FamilyDocument == null)
			{
				this.ClearTempFiles();
				return false;
			}
			FamilySymbol familySymbol = null;
			if (!this.GetSymbol(ref familySymbol))
			{
				this.m_KeyboardHook.HookStop();
				this.ClearTempFiles();
			}
			Transaction transaction = null;
			Element element = null;
			try
			{
				ElementId elementId = null;
				if (!this.Drag(familySymbol, ref elementId))
				{
					this.ClearTempFiles();
					transaction = new Transaction(this.m_Doc);
					transaction.Start("recover");
					this.m_Doc.DeleteElement(familySymbol.Family);
					transaction.Commit();
					return false;
				}
				element = this.m_Doc.GetElement(elementId);
				LocationPoint locationPoint = element.Location as LocationPoint;
				ptInsert = locationPoint.Point;
			}
			catch (Exception)
			{
				this.m_KeyboardHook.HookStop();
				this.ClearTempFiles();
				if (transaction != null)
				{
					transaction.RollBack();
				}
				return false;
			}
			if (!this.ClearTempObjects(element, familySymbol.Family))
			{
				this.m_KeyboardHook.HookStop();
				this.ClearTempFiles();
			}
			this.ClearTempFiles();
			return true;
		}

		private bool GetSymbol(ref FamilySymbol jigType)
		{
			Transaction transaction = null;
			bool result;
			try
			{
				transaction = new Transaction(this.m_Doc);
				transaction.Start("drag");
				this.m_UiApp.ActiveUIDocument.Document.LoadFamily(this.m_FamilyFilePath);
				jigType = this.GetFamilySymbolByName(this.m_FamilyName, this.m_FamilyCreator.SymbolName);
				transaction.Commit();
				result = true;
			}
			catch (Exception)
			{
				if (transaction != null)
				{
					transaction.RollBack();
				}
				result = false;
			}
			return result;
		}

		private bool ClearTempObjects(Element tempInstance, Family tempJigFamily)
		{
			Transaction transaction = null;
			bool result;
			try
			{
				transaction = new Transaction(this.m_Doc);
				transaction.Start("recover");
				this.m_Doc.DeleteElement(tempInstance);
				this.m_Doc.DeleteElement(tempJigFamily);
				transaction.Commit();
				result = true;
			}
			catch (Exception)
			{
				if (transaction != null)
				{
					transaction.RollBack();
				}
				result = false;
			}
			return result;
		}

		private bool OpenAndActiveFamilyTemplateDocument(ref string templateFileName)
		{
			string appRootPath = this.GetAppRootPath();
			string versionNumber = this.m_Revit.Application.Application.VersionNumber;
			templateFileName = string.Concat(new string[]
			{
				templateFileName,
				appRootPath,
				"\\Templates\\",
				versionNumber,
				"\\JIGFamilyTemplate.rft"
			});
			if (!File.Exists(templateFileName))
			{
				throw new Exception("Unsupported version");
			}
			return true;
		}

		private string GetAppRootPath()
		{
			string location = Assembly.GetExecutingAssembly().Location;
			int length = location.LastIndexOf("\\");
			string text = location.Substring(0, length);
			length = text.LastIndexOf("\\");
			return text.Substring(0, length);
		}

		private Result NewFamilyDocument(ref string message)
		{
			string text = "";
			try
			{
				if (!this.OpenAndActiveFamilyTemplateDocument(ref text))
				{
					message = "缺少族模板.";
					return Autodesk.Revit.UI.Result.Failed;
				}
			}
			catch (Exception ex)
			{
				message = ex.Message;
				return Autodesk.Revit.UI.Result.Failed;
			}
			this.m_FamilyDocument = this.m_App.NewFamilyDocument(text);
			if (this.m_FamilyDocument == null)
			{
				message = "缺少族模板.";
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private void DocumentClose()
		{
			this.m_FamilyDocument.Close(false);
		}

		private Result SaveFamilyFile()
		{
			string tempPath = Path.GetTempPath();
			this.m_FamilyName = "HYJIG";
			this.m_FamilyFilePath = tempPath + this.m_FamilyName + ".rfa";
			if (File.Exists(this.m_FamilyFilePath))
			{
				File.Delete(this.m_FamilyFilePath);
			}
			SaveAsOptions saveAsOptions = new SaveAsOptions();
			saveAsOptions.OverwriteExistingFile = true;
			RevitVersionFuncs.SaveAs(this.m_FamilyDocument, this.m_FamilyFilePath, saveAsOptions);
			this.m_FamilyDocument.Close(true);
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private void ClearTempFiles()
		{
			this.DeleteFile(this.m_FamilyFilePath);
			string tempPath = Path.GetTempPath();
			foreach (string text in Directory.GetFiles(tempPath, "*.rfa", SearchOption.TopDirectoryOnly))
			{
				if (text.IndexOf("HYJIG") != -1)
				{
					this.DeleteFile(tempPath + Path.GetFileName(text));
				}
			}
		}

		private bool DeleteFile(string fileFillPath)
		{
			bool result;
			try
			{
				if (File.Exists(fileFillPath))
				{
					File.Delete(fileFillPath);
					result = true;
				}
				else
				{
					result = false;
				}
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		private FamilySymbol GetFamilySymbolByName(string familyName, string symbolName)
		{
			FamilySymbol result = null;
			foreach (Element element in new FilteredElementCollector(this.m_Doc).OfClass(typeof(Family)).ToElements())
			{
				Family family = element as Family;
				if (family != null)
				{
					Category familyCategory = RevitVersionFuncs.GetFamilyCategory(family);
					if (familyCategory != null && familyName.ToUpper().CompareTo(family.Name.ToUpper()) == 0)
					{
						foreach (FamilySymbol familySymbol in family.GetSymbols())
						{
							if (symbolName.ToUpper().CompareTo(familySymbol.Name.ToUpper()) == 0)
							{
								return familySymbol;
							}
						}
					}
				}
			}
			return result;
		}

		private bool Drag(FamilySymbol jigType, ref ElementId newInstanceId)
		{
			this.m_AddedElementIds.Clear();
			this.AddEventOperation();
			this.m_KeyboardHook.HookStart();
			if (this.m_UiApp.ActiveUIDocument == null)
			{
				this.RemoveEventOperation();
				this.m_KeyboardHook.HookStop();
				return false;
			}
			if (!this.PromptForFamilyInstancePlacement(jigType))
			{
				this.RemoveEventOperation();
				this.m_KeyboardHook.HookStop();
				return false;
			}
			this.RemoveEventOperation();
			if (this.m_AddedElementIds.Count == 0)
			{
				this.m_KeyboardHook.HookStop();
				return false;
			}
			newInstanceId = this.m_AddedElementIds[0];
			this.m_KeyboardHook.HookStop();
			return true;
		}

		private bool PromptForFamilyInstancePlacement(FamilySymbol jigType)
		{
			bool result;
			try
			{
				this.m_UiApp.ActiveUIDocument.PromptForFamilyInstancePlacement(jigType);
				result = true;
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				result = true;
			}
			catch (Exception ex)
			{
				string message = ex.Message;
				this.RemoveEventOperation();
				this.m_KeyboardHook.HookStop();
				result = false;
			}
			return result;
		}

		private void AddEventOperation()
		{
			this.m_App.DocumentChanged += this.OnDocumentChanged;
			this.m_App.DocumentClosing += this.OnDocumentClosing;
			this.m_App.DocumentCreating += this.OnDocumentCreating;
			this.m_App.DocumentOpening += this.OnDocumentOpening;
		}

		private void RemoveEventOperation()
		{
			this.m_App.DocumentChanged -= this.OnDocumentChanged;
			this.m_App.DocumentClosing -= this.OnDocumentClosing;
			this.m_App.DocumentCreating -= this.OnDocumentCreating;
			this.m_App.DocumentOpening -= this.OnDocumentOpening;
		}

		private void OnDocumentChanged(object sender, DocumentChangedEventArgs e)
		{
			if (e.GetAddedElementIds().Count == 1)
			{
				this.m_AddedElementIds.AddRange(e.GetAddedElementIds());
				this.m_KeyboardHook.HookStop();
				this.SendESC();
				this.SendESC();
			}
		}

		private void OnDocumentClosing(object sender, DocumentClosingEventArgs e)
		{
			this.m_KeyboardHook.HookStop();
			this.SendESC();
			this.SendESC();
		}

		private void OnDocumentCreating(object sender, DocumentCreatingEventArgs e)
		{
			this.m_KeyboardHook.HookStop();
			this.SendESC();
			this.SendESC();
		}

		private void OnDocumentOpening(object sender, DocumentOpeningEventArgs e)
		{
			this.m_KeyboardHook.HookStop();
			this.SendESC();
			this.SendESC();
		}

		[DllImport("user32.dll")]
		private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

		private void SendESC()
		{
			int bVk = 27;
			int dwFlags = 0;
			int dwFlags2 = 2;
			JigCreator.keybd_event((byte)bVk, 0, dwFlags, 0);
			JigCreator.keybd_event((byte)bVk, 0, dwFlags2, 0);
		}

		private ExternalCommandData m_Revit;

		private UIApplication m_UiApp;

		private UIDocument m_UiDoc;

		private Application m_App;

		private Document m_Doc;

		private Document m_FamilyDocument;

		private JigFamilyCreator m_FamilyCreator;

		private List<ElementId> m_AddedElementIds = new List<ElementId>();

		private string m_FamilyFilePath = "";

		private string m_FamilyName = "";

		private KeyboardHook m_KeyboardHook = new KeyboardHook();
	}
}
